package com.example.im;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.adapter.ChatListAdapter;
import com.example.db.CommonData;
import com.example.model.Friends;
import com.example.model.Msg;
import com.example.model.User;
import com.example.p2p.P2pServerWsMsgHandler;
import com.example.p2p.P2pServerAioListener;
import com.example.p2p.P2pServerIpStatListener;
import com.example.util.BaseActivity;
import com.example.util.MyUtil;
import com.example.websocket.ImConfigConst;
import com.example.websocket.ImMessage;
import com.example.websocket.MyWebSocketClient;
import com.example.websocket.TioWebsocketStarter;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import static com.example.db.CommonData.commonData;

import static com.example.db.CommonData.getDbMsg;
import static com.example.util.MyUtil.changeActivity;
import static com.example.util.MyUtil.exeTask;
import static com.example.util.MyUtil.exeUrlTask;
import static com.example.util.MyUtil.toast;

import org.tio.core.ChannelContext;
import org.tio.websocket.common.WsRequest;

public class ChatActivity extends BaseActivity {
    private Button send_btn;
    private EditText edit;
    private ImageView back;
    private ImageButton del_friend;
    private TextView friend_name;
    private ListView msg_list;
    private ImageButton call_btn;
    private Friends friend;//当前聊天好友
    private Thread websocketThread;
    private MyWebSocketClient webSocketClient;
    private Thread p2pWebsocketThread;
    private MyWebSocketClient p2pWebSocketClient;
    private boolean onCall;
    private WifiP2pManager wifiP2pManager;
    private WifiP2pManager.Channel channel;
    private BroadcastReceiver receiver;
    private WifiP2pDevice serverDevice;
    private Socket socket;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        send_btn = findViewById(R.id.send_btn);
        edit = findViewById(R.id.edit);
        back = findViewById(R.id.back);
        del_friend = findViewById(R.id.del_friend);
        friend_name = findViewById(R.id.friend_name);
        msg_list = findViewById(R.id.msg_list);
        call_btn = findViewById(R.id.call_btn);
        //显示好友姓名 获取好友信息
        friend = commonData.getChatFriend();
        friend_name.setText(friend.getName());
        //初始化消息列表
        initMsg_list();

        onCall = false;

        back.setOnClickListener(v -> {
            //返回首页
            MyUtil.finishChangeActivity(ChatActivity.this, MainActivity.class);
        });


        call_btn.setEnabled(true);
        call_btn.setImageResource(R.drawable.ic_call);

        initP2PButton();

        initP2pServer();


        initSendMsgButton();
        //绑定删除好友事件
        delClick();


    }

    private void initP2pServer() {
        exeTask(() -> {
            P2pServerWsMsgHandler iWsMsgHandler = new P2pServerWsMsgHandler() {
                @Override
                public Object onText(WsRequest wsRequest, String text, ChannelContext channelContext) {
                    if (!hasText(text)) {
                        return null;
                    }
                    try {
                        ImMessage imMessage = JSON.parseObject(text, ImMessage.class);

                        String content = removeHtml(imMessage.getContent());
                        imMessage.setContent(content);

                        // 获取消息并显示
                        if (null != friend) {
                            Msg msg = new Msg();
                            msg.setMsg(imMessage.getContent());
                            msg.setFid(imMessage.getToId());
                            msg.setMid(-1);
                            msg.setSendTime(new Date());
                            msg.setStatus(true);// 已读
                            msg.setUid(imMessage.getFromId());
                            msg.setType(1);
                            CommonData.addDbMsg(commonData.getLoginUserName(), friend.getName(), msg);
                            CommonData.writeData(ChatActivity.this);
                            ((ChatListAdapter) msg_list.getAdapter()).flush(friend);
                        }

                    } catch (Exception e) {
                        Log.e("ChatActivity", "P2P解析消息失败", e);
                    }



                    //返回值是要发送给客户端的内容，一般都是返回null
                    return null;
                }
            };
            TioWebsocketStarter tioWebsocketStarter = new TioWebsocketStarter(iWsMsgHandler, new P2pServerAioListener(), new P2pServerIpStatListener());
            try {
                tioWebsocketStarter.start();
            } catch (Exception e) {
                e.printStackTrace();
                toast(ChatActivity.this, "私聊服务启动失败");
            }
        });
    }


    private void initP2PButton() {
        //点击按钮邀请好友进行p2p私密聊天
        call_btn.setOnClickListener(v -> {
            if (!onCall) {
                AlertDialog alertDialog = new AlertDialog.Builder(this)
                        .setMessage("是否邀请好友进行私密聊天")
                        .setIcon(R.drawable.ic_launcher)
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) {
                                kunP2P();
//                                xiaoQingP2P();
                            }
                        })

                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                            }//添加取消
                        })
                        .create();
                alertDialog.show();
            }

        });
    }

    private synchronized void kunP2P() {
        if (p2pWebSocketClient == null || p2pWebSocketClient.isClosed()) {
            User friendMess = new User();

            //接口获取好友在线状态
            exeUrlTask(this,
                    () -> MyUtil.postReqJson("/admin/user/list",
                            MyUtil.paramMap(Collections.singletonList("userId"),
                                    Collections.singletonList(friend.getFid()))),
                    (res) -> {
                        JSONArray data = res.getDataArray();
                        JSONObject user = data.getJSONObject(0);
                        if (user != null) {
                            friendMess.setId(user.getInteger("id"));
                            friendMess.setName(user.getString("username"));
                            friendMess.setLoginIp(user.getString("loginIp"));
                            friendMess.setPassword(user.getString("password"));

                            synchronized (ChatActivity.this) {
                                if (p2pWebSocketClient == null || p2pWebSocketClient.isClosed()) {
                                    URI serverUri = null;
                                    try {

                                        serverUri = new URI(String.format("ws://%s:%s/%s?uid=%s", friendMess.getLoginIp(), ImConfigConst.SERVER_PORT, ImConfigConst.UID, friendMess.getId()));
                                    } catch (URISyntaxException e) {
                                        throw new RuntimeException(e);
                                    }
                                    p2pWebSocketClient = new MyWebSocketClient(serverUri);

                                    p2pWebsocketThread = MyUtil.exeTask(() -> {
                                        try {
                                            // 建立连接
                                            p2pWebSocketClient.connectBlocking();
                                        } catch (InterruptedException e) {
                                            throw new RuntimeException(e);
                                        }
                                    });
                                }
                            }
                        } else {
                            toast(ChatActivity.this, "对方不在线");
                        }
                    }
            );

        } else {

            p2pWebSocketClient.close();
            p2pWebSocketClient = null;
        }
    }

    private void xiaoQingP2P() {
        //开启监听

        // 初始化 WifiP2pManager
        wifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
        if (wifiP2pManager == null) {
            Toast.makeText(ChatActivity.this, "该设备不支持 Wi-Fi Direct", Toast.LENGTH_SHORT).show();
            return;
        }

        // 初始化 Channel
        channel = wifiP2pManager.initialize(ChatActivity.this, getMainLooper(), null);

        // 注册广播接收器
        receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
                    // Wi-Fi Direct 状态发生变化
                    int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
                    if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                        Log.d("Client", "Wi-Fi Direct 已启用");
                    } else {
                        Log.d("Client", "Wi-Fi Direct 已停用");
                    }

                } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
                    // 设备列表发生变化
                    wifiP2pManager.requestPeers(channel, new WifiP2pManager.PeerListListener() {
                        @Override
                        public void onPeersAvailable(WifiP2pDeviceList peers) {
                            for (WifiP2pDevice device : peers.getDeviceList()) {
                                Log.d("Client", "发现设备：" + device.deviceName + ", " + device.deviceAddress);

                                // 记录服务端设备
                                if (device.deviceName.equals("server")) {
                                    serverDevice = device;
                                }
                            }
                        }
                    });

                } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
                    // 连接状态发生变化
                    NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
                    if (networkInfo.isConnected()) {
                        // 建立连接
                        Log.d("Client", "连接已建立");

                        // 请求连接信息
                        wifiP2pManager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() {
                            @Override
                            public void onConnectionInfoAvailable(WifiP2pInfo info) {
                                if (info.groupFormed && info.isGroupOwner) {
                                    // 服务端不需要做额外处理
                                    Log.d("Client", "该设备为服务端");

                                } else if (info.groupFormed) {
                                    // 客户端发起连接
                                    Log.d("Client", "该设备为客户端");

                                    try {
                                        socket = new Socket();
                                        socket.connect(new InetSocketAddress(serverDevice.deviceAddress, 8888), 5000);
                                        Log.d("Client", "连接服务器成功：" + socket.getInetAddress());

                                        // 向服务端发送数据
                                        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                                        writer.write("Hello, World!");
                                        writer.newLine();
                                        writer.flush();

                                        // 读取服务端响应数据
                                        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                                        String data = reader.readLine();
                                        Log.d("Client", "服务端返回的响应：" + data);

                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        });

                    } else {
                        // 断开连接
                        Log.d("Client", "连接已断开");
                        if (socket != null) {
                            try {
                                socket.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }

                } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
                    // 本设备信息发生变化
                    WifiP2pDevice device = intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
                    Log.d("Client", "本设备信息发生变化：" + device.deviceName + ", " + device.deviceAddress);
                }
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
        filter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
        filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
        filter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
        registerReceiver(receiver, filter);

        // 扫描设备
        wifiP2pManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
            @Override
            public void onSuccess() {
                Log.d("Client", "开始查找设备");
            }

            @Override
            public void onFailure(int reason) {
                Log.d("Client", "查找设备失败：" + reason);
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();

        // 关闭websocket
        if (webSocketClient != null && websocketThread.isAlive()) {
            webSocketClient.close();
            websocketThread.interrupt();
        }

        if (p2pWebSocketClient != null && p2pWebsocketThread.isAlive()) {
            p2pWebSocketClient.close();
            p2pWebsocketThread.interrupt();
        }
    }

    public synchronized void runWebSocketService() {
        if (webSocketClient == null || webSocketClient.isClosed()) {
            URI serverUri = null;
            try {
                serverUri = new URI("ws://1.15.72.167:8082/protocol_poetize?Authorization=" + commonData.getToken());
            } catch (URISyntaxException e) {
                throw new RuntimeException(e);
            }
            webSocketClient = new MyWebSocketClient(serverUri) {
                @Override
                public void onMessage(String message) {
                    super.onMessage(message);
                    // 收到服务器消息处理方法(这个message就是最新未读消息！！)
                    ChatActivity.this.runOnUiThread(() -> {
//                        toast(ChatActivity.this, message);
                        // 刷新信息列表
                        if (msg_list != null) {
                            ((ChatListAdapter) msg_list.getAdapter()).flush(friend);
                        }
                    });
                }
            };

            websocketThread = MyUtil.exeTask(() -> {
                try {
                    // 建立连接
                    webSocketClient.connectBlocking();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    /**
     * 初始化 发送消息按钮 响应事件
     */
    private void initSendMsgButton() {
        send_btn.setOnClickListener(v -> {
            String msg = edit.getText().toString();
            //发送消息接口
            Msg sendMsg = new Msg();
            sendMsg.setSendTime(new Date());
            sendMsg.setMsg(msg);
            sendMsg.setUid(commonData.getUser().getId());
            sendMsg.setFid(friend.getFid());
            sendMsg.setMid(new Random().nextInt());
            sendMsg.setType(0);
            sendMsg.setStatus(false);

            if (p2pWebSocketClient == null || p2pWebSocketClient.isClosed()) {
                // 1.网络请求发送
                sendNetMsg(sendMsg);
            } else {
                // 2. p2p
                sendP2PMsg(sendMsg);
            }


        });
    }

    private void sendP2PMsg(Msg msg) {
        // 1.发送
        exeTask(() -> {
            ImMessage imMessage = new ImMessage();
            imMessage.setContent(msg.getMsg());
            imMessage.setFromId(msg.getUid());
            imMessage.setToId(msg.getFid());
            p2pWebSocketClient.send(JSON.toJSONString(imMessage));
            // 2.本地数据处理
            if (CommonData.addDbMsg(commonData.getLoginUserName(), friend.getName(), msg)) {
                edit.setText("");
                edit.post(() -> ((ChatListAdapter) msg_list.getAdapter()).flush(friend));
            } else {
                // 重新获取所有消息来处理这中异常
//                        toast(ChatActivity.this, "[本地]消息处理失败");
            }
        });

    }

    /**
     * 网络请求，向服务器发送消息（发送给好友）
     *
     * @param msg
     */
    private void sendNetMsg(Msg msg) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("content", msg.getMsg());
        param.put("friendId", msg.getFid());
        MyUtil.exeUrlTask(
                ChatActivity.this,
                () -> MyUtil.postReqParam("/imChatUserMessage/sendFriendMessage", param),
                (res) -> {
                    /*
                    id fromId toId content messageStatus(bool)
                     */
                    // 发送成功
                    JSONObject data = res.getDataObject();
                    msg.setStatus(false);
                    msg.setMsg(data.getString("content"));
                    // 服务器消息0
                    msg.setType(0);
                    msg.setMid(data.getInteger("id"));
                    msg.setUid(data.getInteger("fromId"));
                    msg.setFid(data.getInteger("toId"));

                    // 2.本地数据处理
                    if (CommonData.addDbMsg(commonData.getLoginUserName(), friend.getName(), msg)) {
                        edit.setText("");
                        ((ChatListAdapter) msg_list.getAdapter()).flush(friend);
                    } else {
                        // 重新获取所有消息来处理这中异常
//                        toast(ChatActivity.this, "[本地]消息处理失败");
                    }
                }
        );
    }


    private void delClick() {
        del_friend.setOnClickListener(v -> {
            Map<String, String> friendDel = new HashMap<>();
            //删除好友 给出弹窗
            AlertDialog alertDialog = new AlertDialog.Builder(this)
                    .setTitle("提示")
                    .setMessage("是否删除好友")
                    .setIcon(R.drawable.ic_launcher)
                    .setPositiveButton("确定", new DialogInterface.OnClickListener() {//添加"Yes"按钮
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            friendDel.put("friendStatus", String.valueOf(-1));
                            friendDel.put("friendId", String.valueOf(friend.getFid()));
                            //删除好友接口
                            exeUrlTask(
                                    ChatActivity.this,
                                    () -> MyUtil.getReqParam("/imChatUserFriend/changeFriend",
                                            friendDel),
                                    res -> (ChatActivity.this).runOnUiThread(() -> {
                                        //修改本地数据
                                        CommonData.delDbFriend(commonData.getUser(), friend);
                                        commonData.setChatFriend(null);
                                        toast(ChatActivity.this, "删除好友成功");
                                        //切换到首页
                                        changeActivity(ChatActivity.this, MainActivity.class);

                                    }),
                                    res -> (ChatActivity.this).runOnUiThread(() -> {
                                        toast(ChatActivity.this, res.getMessage());
                                        //切换到首页
                                        changeActivity(ChatActivity.this, MainActivity.class);
                                    })
                            );
                        }
                    })

                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {

                        }//添加取消
                    })
                    .create();
            alertDialog.show();
        });
    }

    private void initMsg_list() {
        //初始化消息列表
        List<Msg> msgList = getDbMsg(commonData.getUser().getName(), commonData.getChatFriend().getName());
        msg_list.setAdapter(new ChatListAdapter(this, msgList));
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (null != friend) {
            ((ChatListAdapter) msg_list.getAdapter()).flush(friend);
        }
        runWebSocketService();
    }
}
